﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Lime49;

namespace LaunchMeNot.Core {
    /// <summary>
    /// An entry managed by LaunchMeNot.
    /// </summary>
    public class LaunchMeNotEntry : StartupEntryBase {
        protected string _id,
                         _description;
        protected int _launchOrder = 0;
        protected double _launchDelay = CoreConfigurationManager.DefaultLaunchDelay;
        protected bool _isEnabled = true;

        /// <summary>
        /// Gets or sets unique ID of this entry.
        /// </summary>
        /// <value>The entry ID.</value>
        public string ID {
            get { return _id; }
            set {
                _id = value;
                OnPropertyChanged("ID");
            }
        }

        /// <summary>
        /// Gets or sets the description of the shortcut.
        /// </summary>
        /// <value>The description of the shortcut.</value>
        public string Description
        {
            get { return _description; }
            set
            {
                _description = value;
                OnPropertyChanged("Description");
            }
        }

        /// <summary>
        /// Gets or sets the order in which this entry should be launched.
        /// </summary>
        /// <value>The order in which this entry should be launched.</value>
        public int LaunchOrder {
            get { return _launchOrder; }
            set {
                _launchOrder = value;
                OnPropertyChanged("LaunchOrder");
            }
        }

        /// <summary>
        /// Gets or sets the number of seconds to wait after launching this application.
        /// </summary>
        /// <value>The number of seconds to wait after launching this application.</value>
        public double LaunchDelay
        {
            get { return _launchDelay; }
            set
            {
                _launchDelay = value;
                OnPropertyChanged("LaunchDelay");
            }
        }

        /// <summary>
        /// Gets or sets a value whether this entry should be launched on startup.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this entry should be launched on startup, otherwise <c>false</c>.
        /// </value>
        public bool IsEnabled {
            get { return _isEnabled; }
            set {
                _isEnabled = value;
                OnPropertyChanged("IsEnabled");
            }
        }

        /// <summary>
        /// Initializes a new, blank <see cref="LaunchMeNotEntry"/>.
        /// </summary>
        public LaunchMeNotEntry()
            : base() {
            this.ID = Lime49.Utils.GenID(true);
            this.Description = string.Empty;
            this.IsEnabled = true;
            this.LaunchOrder = 0;
            EntryType = StartupEntryType.LaunchMeNot;
            // launch delay set at declaration
        }

        /// <summary>
        /// Initializes a new <see cref="StartupEntryBase"/> from an existing file path.
        /// </summary>
        /// <param name="fileName">Full path of the file.</param>
        public LaunchMeNotEntry(string fileName) 
            :base(fileName){
                this.ID = Lime49.Utils.GenID(true);
                this.Description = string.Empty;
                EntryType = StartupEntryType.LaunchMeNot;
        }

        /// <summary>
        /// Initializes a new <see cref="LaunchMeNotEntry"/>.
        /// </summary>
        public LaunchMeNotEntry(string name, string path, string arguments)
            : base(name, path, arguments) {
            this.ID = Lime49.Utils.GenID(true);
            this.Description = string.Empty;
            EntryType = StartupEntryType.LaunchMeNot;
        }

        /// <summary>
        /// Initializes a new <see cref="LaunchMeNotEntry"/>.
        /// </summary>
        public LaunchMeNotEntry(string id, string name, string path, string arguments)
            : this(name, path, arguments) {
            this.ID = id;
            this.Description = string.Empty;
        }

        /// <summary>
        /// Initializes a new <see cref="LaunchMeNotEntry"/>.
        /// </summary>
        /// <param name="element">The element containing the entry data.</param>
        public LaunchMeNotEntry(XElement element) 
            :this(){
                var dummyAttribute = new XAttribute("dummy", string.Empty);
            try {
                this.ID = HtmlUtils.HtmlDecode(element.Attribute("id").Value);
                this.Description = HtmlUtils.HtmlDecode((element.Attribute("description") ?? dummyAttribute).Value);
                this.Arguments = HtmlUtils.HtmlDecode(element.Attribute("arguments").Value);
                this.LaunchDelay = Convert.ToDouble(element.Attribute("launchdelay").Value);
                this.LaunchOrder = Convert.ToInt32(element.Attribute("launchorder").Value);
                this.IsEnabled = Convert.ToBoolean(element.Attribute("enabled").Value);
                this.Name = HtmlUtils.HtmlDecode(element.Element("name").Value);
                this.Path = HtmlUtils.HtmlDecode(element.Element("filepath").Value);
                EntryType = StartupEntryType.LaunchMeNot;
            } catch {
                throw new Exception("Invalid entry");
            }
        }

        /// <summary>
        /// Initializes a new <see cref="LaunchMeNotEntry"/> from an existing entry.
        /// </summary>
        /// <param name="entry">The entry.</param>
        public LaunchMeNotEntry(IStartupEntry entry) 
            :this() {
            this.Arguments = entry.Arguments;
            this.Name = entry.Name;
            this.Path = entry.Path;
            if (entry is LaunchMeNotEntry) {
                var realEntry = ((LaunchMeNotEntry)entry);
                this.Description = realEntry.Description;
                this.ID = realEntry.ID;
                this.IsEnabled = realEntry.IsEnabled;
                this.LaunchDelay = realEntry.LaunchDelay;
                this.LaunchOrder = realEntry.LaunchOrder;
            } else if (entry is ShellShortcut) {
                this.Description = ((ShellShortcut)entry).Description;
            }
            EntryType = StartupEntryType.LaunchMeNot;
        }

        /// <summary>
        /// Converts this entry to an XElement for serialization.
        /// </summary>
        /// <returns>This entry as an XElement.</returns>
        public XElement ToXElement() {
            XElement element = new XElement("entry",
                new XAttribute("id", HtmlUtils.HtmlEncode(this.ID)),
                new XAttribute("description", HtmlUtils.HtmlEncode(this.Description)),
                new XAttribute("arguments", HtmlUtils.HtmlEncode(this.Arguments)),
                new XAttribute("launchdelay", Convert.ToString(this.LaunchDelay)),
                new XAttribute("launchorder", Convert.ToString(this.LaunchOrder)),
                new XAttribute("enabled", Convert.ToString(this.IsEnabled)),
                new XElement("name", HtmlUtils.HtmlEncode(this.Name)),
                new XElement("filepath", HtmlUtils.HtmlEncode(this.Path))
                );
            return element;
        }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns>A deep copy of this entry.</returns>
        public override IStartupEntry Clone() {
            var entry = new LaunchMeNotEntry()
            {
                ID = this.ID,
                Description = this.Description,
                Arguments = this.Arguments,
                IsEnabled = this.IsEnabled,
                LaunchOrder = this.LaunchOrder,
                LaunchDelay = this.LaunchDelay,
                Name = this.Name,
                Path = this.Path,
                EntryType = StartupEntryType.LaunchMeNot
            };
            return entry;   
        }
    }
}